package com.stox.ui.javafx.list.view;

import java.util.List;
import java.util.Locale;

import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.TreeView.EditEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Screen;
import javafx.util.Callback;
import jfxtras.scene.control.window.WindowIcon;
import lombok.Delegate;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.stox.dto.AbstractModel;
import com.stox.dto.WatchList;
import com.stox.dto.intf.AbstractModelNavigable;
import com.stox.ui.javafx.core.model.TreeViewAbstractModelSearchable;
import com.stox.ui.javafx.core.util.ExceptionHandler.ExceptionHandlingRunnable;
import com.stox.ui.javafx.core.view.View;
import com.stox.ui.javafx.core.widget.AbstractModelSearchPanel;
import com.stox.ui.javafx.core.widget.AbstractModelTreeView;
import com.stox.ui.javafx.core.widget.StoxStage;
import com.stox.ui.javafx.list.client.WatchListClient;
import com.stox.ui.javafx.list.event.handler.WatchlistCellDragDroppedEventHandler;
import com.stox.ui.javafx.list.event.handler.WatchlistCellDragOverEventHandler;
import com.stox.ui.javafx.list.widget.WatchListTreeItem;
import com.stox.ui.javafx.list.widget.WatchlistCell;
import com.stox.ui.javafx.list.widget.menu.WatchListContextMenu;
import com.stox.ui.javafx.list.widget.menu.WatchListMenu;

@Component
public class WatchListView extends View implements InitializingBean, AbstractModelNavigable<List<AbstractModel>>{
	private static final long serialVersionUID = 1L;

	private static WatchListView instance;
	
	public static WatchListView getInstance(){
		return instance;
	}
	
	@Autowired
	private ApplicationContext applicationContext;
	
	@Autowired
	private WatchListClient watchListClient;
	
	@Autowired
	private WatchListContextMenu watchListContextMenu;
	
	@Autowired
	private WatchlistCellDragOverEventHandler watchlistCellDragOverEventHandler;
	
	@Autowired
	private WatchlistCellDragDroppedEventHandler watchlistCellDragDroppedEventHandler;
	
	@Autowired
	private AbstractModelSearchPanel abstractModelSearchPanel;
	
	@Autowired
	private AbstractModelTreeView treeView;
	
	@Delegate
	private final TreeViewAbstractModelSearchable treeViewabstractModelSearchable = new TreeViewAbstractModelSearchable();
	
	private BorderPane contentPane = new BorderPane();
	
	@Override
	public void afterPropertiesSet() throws Exception {
		instance = this;
		setTitle(applicationContext.getMessage("application.name.list", null, Locale.getDefault()));
		treeViewabstractModelSearchable.setTreeView(treeView);
		treeView.setContextMenu(watchListContextMenu);
		
		abstractModelSearchPanel.setabstractModelSearchable(treeViewabstractModelSearchable);
		contentPane.setBottom(abstractModelSearchPanel);
		getContentPane().getChildren().add(contentPane);
		
		
		treeView.setShowRoot(false);
		treeView.setEditable(true);
		treeView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
		
		treeView.setOnEditCommit(new EventHandler<EditEvent<AbstractModel>>(){
			@Override
			public void handle(EditEvent<AbstractModel> event) {
				watchListClient.rename(event.getNewValue().getId(), event.getNewValue().getName());
				
				for(WatchListMenu watchListMenu : WatchListMenu.getWatchListMenus()){
					if(watchListMenu.getWatchList().getId().equals(event.getNewValue().getId())){
						watchListMenu.getWatchList().setName(event.getNewValue().getName());
						watchListMenu.setText(event.getNewValue().getName());
					}
				}
			}
		});
		
		treeView.setCellFactory(new Callback<TreeView<AbstractModel>, TreeCell<AbstractModel>>() {
			@Override
			public TreeCell<AbstractModel> call(TreeView<AbstractModel> treeView) {
				WatchlistCell cell = new WatchlistCell();
				cell.setOnDragOver(watchlistCellDragOverEventHandler);
				cell.setOnDragDropped(watchlistCellDragDroppedEventHandler);
				return cell;
			}
		});
		
		WindowIcon addWatchListButton = new WindowIcon();
		addWatchListButton.getStyleClass().add("plus-button");
		getRightIcons().add(0,addWatchListButton);
		addWatchListButton.setOnAction(new EventHandler<ActionEvent>(){
			@Override
			public void handle(ActionEvent arg0) {
				TreeItem<AbstractModel> newTreeItem = applicationContext.getBean(WatchListTreeItem.class);
				WatchList newWatchList = createEmptyWatchList(); 
				newTreeItem.setValue(newWatchList);
				treeView.getRoot().getChildren().add(0, newTreeItem);
			}
		});	
	}
	
	private WatchList createEmptyWatchList(){
		WatchList watchList = new WatchList();
		watchList.setName(applicationContext.getMessage("NewWatchList", null, Locale.getDefault()));
		watchList.setId(watchListClient.save(watchList));
		return watchList;
	}
	
	public TreeItem<AbstractModel> getWatchListTreeItemById(Long id){
		return getWatchListTreeItemById(treeView.getRoot(), id);
	}
	
	private TreeItem<AbstractModel> getWatchListTreeItemById(TreeItem<AbstractModel> treeItem, Long id){
		if(null != treeItem && 
			null != treeItem.getValue() &&
			(treeItem.getValue() instanceof WatchList) &&
			(	id == treeItem.getValue().getId() || 
				(	null != id && 
					null != treeItem.getValue().getId() && 
					id.equals(treeItem.getValue().getId())))){
			return treeItem;
		}
		
		if(null != treeItem && null != treeItem.getChildren() && !treeItem.getChildren().isEmpty()){
			for(TreeItem<AbstractModel> child : treeItem.getChildren()){
				TreeItem<AbstractModel> result = getWatchListTreeItemById(child, id);
				if(null != result){
					return result;
				}
			}
		}
		
		return null;
	}
	
	private void setPosition(){
		Bounds bounds = StoxStage.getInstance().getContentPane().getBoundsInParent();
		setLayoutX(bounds.getMaxX() - getPrefWidth());
		setLayoutY(bounds.getMaxY() - getPrefHeight());
	}
	
	@Override
	public void open() {
		new Thread(new ExceptionHandlingRunnable(){
			public void doRun(){
				if(null != treeView && null != treeView.getRoot()) return;
				WatchListTreeItem root = applicationContext.getBean(WatchListTreeItem.class);
				Platform.runLater(new ExceptionHandlingRunnable(){
					@Override
					public void doRun() {
						root.setValue(new WatchList());
						contentPane.setCenter(treeView);
						treeView.setRoot(root);
						treeView.getRoot().setExpanded(true);
						treeView.layout();
					}
				});
			}
		}).start();
		setPrefWidth(Screen.getPrimary().getVisualBounds().getWidth()/5);
		setPrefHeight(StoxStage.getInstance().getContentPane().getBoundsInLocal().getHeight()/2);
		setPosition();
		super.open();
	}
		
}
